#include "send_msg.h"
#include "unicodelib.h"
#include "utf_ucs2.h"

int readable_timeo(int fd, int sec)
{
	fd_set rset;
	struct timeval	tv;

	FD_ZERO(&rset);
	FD_SET(fd, &rset);

	tv.tv_sec = sec;
	tv.tv_usec= 0;

	return(select(fd+1, &rset, NULL, NULL, &tv));
	/*> 0 有文件描述符可读， =0 超时 < 0 无描述符可读*/
}

/***************************************
 *name    : recv_msg
 *功能描述: 利用文本模式接收短信息，有效信息 gbdq1, dkdq1,dkgq2, gbdq2, gbjk, dkjk
 *入口参数: fd 串口文件描述符
 *返 回 值: 返回成功设置的stat值
 *作    者: fens
 *最后修改: 2011.4.28
 ***************************************/
int recv_msg(int fd)
{   
    char read_buf[512],*str = NULL;
    int stat = 0;

    memset(read_buf, 0, sizeof(read_buf));

    write(fd, "AT\r", 3);
    usleep(1000);
    read(fd, read_buf, sizeof(read_buf));
    printf("connect %s\n",read_buf);
    
    write(fd, "AT+CMGF=1\r",10);  //接收模式选择文本模式
    usleep(1000);
    read(fd,read_buf, sizeof(read_buf));
    printf("mode: %s\n", read_buf);
    
    write(fd, "AT+CMGL=\"ALL\"\r", strlen("AT+CMGL=\"ALL\"\r")); //读取所有短信
    sleep(2);
    read(fd,read_buf, sizeof(read_buf));
    sleep(1);
    printf("read:%s\n",read_buf); 
         
    if((str = strstr(read_buf, "UNREAD")) != NULL){ //判断是否有新消息
        printf("str = %s\n", str); 
            
        if(strstr(str, "dkjd1") || strstr(str, "DKJD1")){
            printf("Device1 on\n");
            stat = 0;
        }
        else if(strstr(str, "gbjd1") || strstr(str, "GBJD1")){
            printf("Device1 off\n");
            stat = 1;
        }
        else if(strstr(str, "dkjd2") || strstr(str, "DKJD2")){
            printf("Device2 on\n");
            stat = 2;
        }
        else if(strstr(str, "gbjd2") || strstr(str, "GBJD2")){
            printf("Device2 off\n");
            stat = 3;
        }
        else if(strstr(str, "dkjk") || strstr(str, "DKJK")){
            printf("OpenInspect\n");
            stat = 4;
        }
        else if(strstr(str, "gbjk") || strstr(str, "GBJK")){
            printf("CloseInspect\n");
            stat = 5;
        }

            //删除已读取的信息
        sprintf(read_buf,"AT+CMGD=%c\r",*(str-7));
        write(fd, read_buf,10);
        sleep(1);
        read(fd, read_buf, sizeof(read_buf));
        printf("delete the new message %s\n", read_buf);
        
        return stat;
    }
    
    return -1;    
}
/***************************************
*功能描述：	Unicode转汉字
*入口参数: 	iUnicode - 一个Unicode编码  	
*输    出:	无
*返 回 值: 	返回GB中文编码
*作	   者： fens
*最后修改：	2011-5-4
****************************************/
unsigned short Unicode2GBcode(unsigned short iUnicode)
{
	int i, j, n;
	int low, high, mid;

	switch (iUnicode)
	{
		case 0x0002:
		{
			return 0x24;
			break;
		}
		case 0x000a:
		{
			return 0xa;
			break;
		}
		case 0x000d:
		{
			return 0xd;
			break;
		}
		case 0x0040:
		{
			return 0xA1;
			break;
		}
		default:break;
	}

	if ((iUnicode >= 0x20 && iUnicode <= 0x5a) || (iUnicode >= 0x61 && iUnicode
			<= 0x7e))
		return iUnicode;

	n = sizeof(Unicode_GB2312) / sizeof(Unicode_GB2312[0]) - 1;
	low = 0;
	high = n;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (Unicode_GB2312[mid][0] == iUnicode)
		{
			return Unicode_GB2312[mid][1];
		}
		if (iUnicode > Unicode_GB2312[mid][0])
			low = mid + 1;
		else
			high = mid - 1;
	}

	return 0;


	for (i = 0, j = 0, n = sizeof(Unicode_GB2312) / sizeof(Unicode_GB2312[0])- 1; n > 0; n >>= 1, ++j)
	{
		if (Unicode_GB2312[i][0] == iUnicode)
		{
			printf("\nUnicode_GB2312[%d][1]=[%x]", i, Unicode_GB2312[i][1]);
			return Unicode_GB2312[i][1];
		}

		if (j > 1)
		{
			if (Unicode_GB2312[i - 1][0] == iUnicode)
				return Unicode_GB2312[i - 1][1];
			if (Unicode_GB2312[i + 1][0] == iUnicode)
				return Unicode_GB2312[i + 1][1];
		}

		if (Unicode_GB2312[i][0] < iUnicode)
			i = i + n;
		else
			i = i - n;
	}

	if (Unicode_GB2312[i][0] == iUnicode)
		return Unicode_GB2312[i][1];
	if (Unicode_GB2312[i - 1][0] == iUnicode)
		return Unicode_GB2312[i - 1][1];
	if (Unicode_GB2312[i + 1][0] == iUnicode)
		return Unicode_GB2312[i + 1][1];

	return 0; 
}

/***************************************
*功能描述：	Unicode串GB汉字字符串
*入口参数: 	strSourcer - 源字符串指针
*          	n - 源字符串长度
*输    出:	strDest - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者： fens
*最后修改：	2011-5-4
****************************************/
int strUnicode2GB(const unsigned char *strSourcer, char *strDest, int n)
{
	char cTmp;
	unsigned short hz, tmphz;

	const unsigned char *pSrc;
	char *pDest;
	int i;

	for (i = 0, pSrc = strSourcer, pDest = strDest; n > 0; n -= 2, pSrc += 2, ++i, ++pDest)
	{

		hz = 0;
		hz = *pSrc << 8 | (*(pSrc + 1) & 0x00FF);
		tmphz = Unicode2GBcode(hz);

		if (!tmphz || (tmphz > 0x7F && tmphz < 0xFF))
		{
			*pDest = '.';
			++pDest;
			*pDest = '.';
			continue;
		}
		else if (tmphz > 0x00 && tmphz <= 0x7F)
		{
			cTmp = tmphz;
			*pDest = cTmp;
		}
		else
		{
			cTmp = tmphz;
			*pDest = (tmphz >> 8);
			++pDest;
			*pDest = cTmp;
		}
	}

	*pDest = '\0';
	return i;

}
/***************************************
*功能描述：	汉字字符串转Unicode串
*入口参数: 	str - 源字符串指针
*          	n - 源字符串长度
*输    出:	dst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int strGB2Unicode(const char *str, unsigned char *dst, int n)
{
	int j = 0;
	unsigned int k = 0;
	int i = 0;
    unsigned char *s = dst;
    unsigned short int tmp = 0;
  	int len = strlen(str);
  
	if (!str)
		return -1;
		
	while (i < len)
	{
		if ((unsigned char) str[i] < 0xa1)
		{
		    s[j++] = 0x0;
			s[j++] = str[i++];			
		}
		else
		{
			tmp = str[i] & 0xff;		//先取高八位
			tmp = ((tmp << 8) & 0xff00) | (str[i + 1] & 0xff);  //将高八位于低八位组合成二字节整数 一个汉字
			i += 2;
			for (k = 0; k < sizeof(Unicode_GB2312) / sizeof(Unicode_GB2312[0])   //计算字库里面的数量
					- 1; k++)
			{
				if (tmp == Unicode_GB2312[k][1])
				{
					s[j++] = (Unicode_GB2312[k][0] >> 8) & 0xff;  //取高八位，如“发“ Unicode_Gb2312[k][0] = 0x53D1
					s[j++] = Unicode_GB2312[k][0] & 0xff;		 //将低八位存储在下一个位置 s[0] = 0x53, s[1] = 0xD1
					break;
				}
			}
			/*没找到*/
			if (k == sizeof(Unicode_GB2312) / sizeof(Unicode_GB2312[0]) - 1)
				{
				return 0;
				}
		}
	}
	s[j] ='\0';
	return j;

}

/***************************************
*功能描述：	字符串转换为字节数据 , 如："C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01}
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int String2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
	int i;
	for (i = 0; i < nSrcLength; i += 2)
	{
		// 输出高4位
		if ((*pSrc >= '0') && (*pSrc <= '9'))
		{
			*pDst = (*pSrc - '0') << 4;
		}
		else
		{
			*pDst = (*pSrc - 'A' + 10) << 4;
		}

		pSrc++;

		// 输出低4位
		if ((*pSrc>='0') && (*pSrc<='9'))
		{
			*pDst |= *pSrc - '0';
		}
		else
		{
			*pDst |= *pSrc - 'A' + 10;
		}

		pSrc++;
		pDst++;
	}

	// 返回目标数据长度
	return (nSrcLength / 2);
}

/***************************************
*功能描述：	字节数据转换为可打印字符串,如：{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01" 
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int Bytes2String(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
	const char tab[]="0123456789ABCDEF";	// 0x0-0xf的字符查找表
	int i;
	for (i = 0; i < nSrcLength; i++)
	{
		*pDst++ = tab[*pSrc >> 4];		// 输出高4位
		*pDst++ = tab[*pSrc & 0x0f];	// 输出低4位
		pSrc++;
	}

	// 输出字符串加个结束符
	*pDst = '\0';

	// 返回目标字符串长度
	return (nSrcLength * 2);
}

/***************************************
*功能描述：	将正常顺序的字符串转换成奇偶位交换的字符串 长度为奇数则补'F'.如："8613633838481" --> "683136838384F1"
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int convertNumbers(const char* pSrc, char* pDst, int nSrcLength)
{
	int nDstLength;		
	char ch;			
	int i=0;
	// 复制串长度
	nDstLength = nSrcLength;
	for(i = 0; i < nSrcLength;i += 2)
	{
		ch = *pSrc++;		
		*pDst++ = *pSrc++;	 
		*pDst++ = ch;		 
	}

	 
	if(nSrcLength & 1)
	{
		*(pDst-2) = 'F';	// 补'F'
		nDstLength++;		 
	}

	*pDst = '\0';

	return nDstLength;
}

/***************************************
*功能描述：	将奇偶调换的字符串转换为正常顺序的字符串 如："683136838384F1" --> "8613633838481"
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int uconvertNumbers(const char* pSrc, char* pDst, int nSrcLength)
{
	int nDstLength;		 
	char ch;			 
	int i;
 
	nDstLength = nSrcLength; 
	for(i = 0; i < nSrcLength; i += 2)
	{
		ch = *pSrc++;		 
		*pDst++ = *pSrc++;	 
		*pDst++ = ch;		 
	}
 
	if(*(pDst-1) == 'F')
	{
		pDst--;
		nDstLength--;		 
	}
 
	*pDst = '\0';
 
	return nDstLength;
}

/***************************************
*功能描述：	7bit编码
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int Encode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
	int nSrc;		
	int nDst;		
	int nChar;		
	unsigned char nLeft;	

	// 计数值初始化
	nSrc = 0;
	nDst = 0;


	while (nSrc < nSrcLength)
	{
		nChar = nSrc & 7;

		// 处理源串的每个字节
		if(nChar == 0)
		{
			nLeft = *pSrc;
		}
		else
		{
			*pDst = (*pSrc << (8-nChar)) | nLeft;

			nLeft = *pSrc >> nChar;
			
			pDst++;
			nDst++;
		}

		// 修改源串的指针和计数值
		pSrc++;
		nSrc++;
	}

	// 返回目标串长度
	return nDst;
}

/***************************************
*功能描述：	7bit解码
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int Decode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
	int nSrc;		
	int nDst;		 
	int nByte;		// 当前正在处理的组内字节的序号，范围是0-6
	unsigned char nLeft;	// 上一字节残余的数据

	// 计数值初始化
	nSrc = 0;
	nDst = 0;
	
	// 组内字节序号和残余数据初始化
	nByte = 0;
	nLeft = 0;

	// 将源数据每7个字节分为一组，解压缩成8个字节
	// 循环该处理过程，直至源数据被处理完
	// 如果分组不到7字节，也能正确处理
	while(nSrc<nSrcLength)
	{
		// 将源字节右边部分与残余数据相加，去掉最高位，得到一个目标解码字节
		*pDst = ((*pSrc << nByte) | nLeft) & 0x7f;

		// 将该字节剩下的左边部分，作为残余数据保存起来
		nLeft = *pSrc >> (7-nByte);

		// 修改目标串的指针和计数值
		pDst++;
		nDst++;

		// 修改字节计数值
		nByte++;

		// 到了一组的最后一个字节
		if(nByte == 7)
		{
			// 额外得到一个目标解码字节
			*pDst = nLeft;

			// 修改目标串的指针和计数值
			pDst++;
			nDst++;

			// 组内字节序号和残余数据初始化
			nByte = 0;
			nLeft = 0;
		}

		// 修改源串的指针和计数值
		pSrc++;
		nSrc++;
	}

	// 输出字符串加个结束符
	*pDst = '\0';

	// 返回目标串长度
	return nDst;
}
/***************************************
*功能描述：	8bit编码
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int Encode8bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
	// 简单复制
	memcpy(pDst, pSrc, nSrcLength);

	return nSrcLength;
}

/***************************************
*功能描述：	8bit解码
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int Decode8bit(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
	// 简单复制
	memcpy(pDst, pSrc, nSrcLength);

	// 输出字符串加个结束符
	*pDst = '\0';

	return nSrcLength;
}

/***************************************
*功能描述：	将汉字转换为UCS2编码
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*最后修改：	2011-5-4
****************************************/
int EncodeUcs2(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
	int nDstLength;		// UNICODE宽字符数目
	unsigned char wchar[256] = {0};	// UNICODE串缓冲区
	int i;
	// 字符串-->UNICODE串
	//nDstLength = strGB2Unicode(pSrc, wchar, nSrcLength);
    char* unicode = utf82unicode(pSrc,(size_t *)&nDstLength);
	
	memcpy(wchar, unicode, nDstLength*2);
	free(unicode);
	
	printf("-%s---len: %d\n", pSrc, nDstLength);
	
#if 1	
	// 高低字节对调，输出
	for(i = 0; i < nDstLength*2; i++)
	{
		if ( i % 2 )
			pDst[i] = wchar[i-1] & 0xff;
		else 
			pDst[i] = wchar[i+1] & 0xff;
	}
#endif

	// 返回目标编码串长度
	return nDstLength*2;
}
/***************************************
*功能描述：	用于编码短信结构，将定义的结构中的数据按照PDU编码方式连接到一起
*入口参数: 	pSrc - 源字符串指针
*          	nSrcLength - 源字符串长度
*输    出:	pDst - 目标编码串指针
*返 回 值: 	目标编码串长度
*作	   者：
*最后修改：	2011-5-4
****************************************/
int EncodePdu(const SM_PARAM* pSrc, char* pDst)
{
	int nLength;			// 内部用的串长度
	int nDstLength;			// 目标PDU串长度
	unsigned char buf[256];	// 内部用的缓冲区

	// SMSC地址信息段
	nLength = strlen(pSrc->SCA);	// SMSC地址字符串的长度	
	buf[0] = (char)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1;	// SMSC地址信息长度
	buf[1] = 0x91;		// 固定: 用国际格式号码
	nDstLength = Bytes2String(buf, pDst, 2);		// 转换2个字节到目标PDU串
	nDstLength += convertNumbers(pSrc->SCA, &pDst[nDstLength], nLength);	// 转换SMSC号码到目标PDU串

	// TPDU段基本参数、目标地址等
	nLength = strlen(pSrc->TPA);	// TP-DA地址字符串的长度
	buf[0] = 0x11;					// 是发送短信(TP-MTI=01)，TP-VP用相对格式(TP-VPF=10)
	buf[1] = 0;						// TP-MR=0
	buf[2] = (char)nLength;			// 目标地址数字个数(TP-DA地址字符串真实长度)
	buf[3] = 0x91;					// 固定: 用国际格式号码
	nDstLength += Bytes2String(buf, &pDst[nDstLength], 4);		// 转换4个字节到目标PDU串
	nDstLength += convertNumbers(pSrc->TPA, &pDst[nDstLength], nLength);	// 转换TP-DA到目标PDU串

	// TPDU段协议标识、编码方式、用户信息等
	nLength = strlen(pSrc->TP_UD);	// 用户信息字符串的长度
	buf[0] = pSrc->TP_PID;			// 协议标识(TP-PID)
	buf[1] = pSrc->TP_DCS;			// 用户信息编码方式(TP-DCS)
	buf[2] = 0xA7;						// 有效期(TP-VP)为5分钟
	if(pSrc->TP_DCS == GSM_7BIT)	
	{
		// 7-bit编码方式
		buf[3] = nLength;			// 编码前长度
		nLength = Encode7bit(pSrc->TP_UD, &buf[4], nLength+1) + 4;	// 转换TP-DA到目标PDU串
	}
	else if(pSrc->TP_DCS == GSM_UCS2)
	{
		// UCS2编码方式
		int len = EncodeUcs2(pSrc->TP_UD, &buf[4], nLength);	// 转换TP-DA到目标PDU串
		buf[3] = len & 0xff;
		nLength = len + 4;		// nLength等于该段数据长度
	}
	else
	{		
		// 8-bit编码方式
		buf[3] =  Encode8bit(pSrc->TP_UD, &buf[4], nLength);	// 转换TP-DA到目标PDU串		
		nLength = buf[3] + 4;		// nLength等于该段数据长度
	}
	nDstLength += Bytes2String(buf, &pDst[nDstLength], nLength);		// 转换该段数据到目标PDU串
	
	
	// 返回目标字符串长度
	return nDstLength;
}

static int GetSmsCenterNo( int fd, char *pbuf )
{
	char buf[128] = {0};
	
	//查询短信中心号
	int ret = write(fd, "AT+CSCA?\r\n", sizeof("AT+CSCA?\r\n"));
	if ( ret <= 0 )
	{
		printf(" send AT+CSCA? error!\n");
		return -1;
	}
	
	ret = readable_timeo( fd, 2);
	if ( ret <= 0 )
	{		
		printf(" read sms center no ack timeout!\n");
		return -1;
	}
	ret = read(fd, buf, sizeof(buf));
	
	printf("read center no ack:%d, %s\n",ret, buf);
	if ( (ret > 0) &&  strstr(buf, "OK") )
	{
		char *pstart = strstr(buf, "+86");
		if ( pstart != NULL )
		{	
	 		pstart += 1;
			strncpy(pbuf, pstart, 13);
			pbuf[13] = '\0';
			printf("read center no: %s\n", pbuf);
			return 0;
		}
	}	

	printf(" read sms center no ack error\n");
	
	return -1;
}
/*****************************************
*功能描述：将短信内容和手机号封装PDU 短信包，并发送
*入口参数：fd 串口的文件描述符，msg 要发送的短信内容指针， phone 要发送的目的手机号码指针
*输	   出：无
*返 回 值：成功返回0 失败返回-1
*作	   者：吴权威
*最后修改：2011-5-4
*****************************************/
int send_msg(int fd, char *msg, char *phone)
{
	char msg_buf[512],buf[64];
	int  msg_len;
	
	SM_PARAM sms;
	bzero(&sms, sizeof(SM_PARAM));
	int ret = GetSmsCenterNo(fd, sms.SCA);  //设置短信中心号（此处为移动的某地中心号）8613800371500
	if ( ret < 0 )
	{
		return -1;
	}	
	
	sprintf(sms.TPA,"86%s", phone);
	sms.TP_PID = 0;
	sms.TP_DCS = 8;
	strncpy(sms.TP_UD, msg,strlen(msg)+1);
	
	msg_len = EncodePdu(&sms, msg_buf);   //封装短信包
	
	/*发送短信*/
	write(fd, "AT\r", 3);
	usleep(1000);
	read(fd, buf, sizeof(buf));
	printf("test connect... %s\n", buf);
	
	write(fd, "AT+CMGF=0\r\n", 11);
	usleep(2000);
	read(fd, buf, sizeof(buf));
	printf("set mode... %s\n", buf);
#if 1	
	printf("AT+CMGS= : %d\n",msg_len/2 -9);
	snprintf(buf, 12, "AT+CMGS=%d\r\n",msg_len/2 -9);   //msg的长度是减掉中心号的长度
	write(fd, buf, strlen(buf));			//发送信息的长度
	usleep(2000);
	ret = readable_timeo( fd, 2);
	if ( ret <= 0 )
	{		
		printf("recv AT+CMGS ack timeout \n");
		return -1;
	}
	read(fd, buf, sizeof(buf));
#endif	
	sprintf(msg_buf, "%s\x1a", msg_buf);
	printf("msg_len : %d, msg = %s\n",msg_len, msg_buf);
	//return -1;
	
	write(fd, msg_buf, strlen(msg_buf));	//发送短信息			
	sleep(3);
	printf("wait send ack.\n");
	bzero(buf, sizeof(buf));
	read(fd, buf, sizeof(buf));
	sleep(1);
	printf("ack: %s\n", buf);
	if(strstr(buf, "ERROR") != NULL){
		printf("send message faild! %s\n", buf);
		return -1;
		}
	else 
		printf("send message success!\n");
		
	return 0;
}

